/*****************************************************************
 *                    XML NSIS plugin v2.0                       *
 *                                                               *
 * 2008 Shengalts Aleksander aka Instructor (Shengalts@mail.ru)  *
 http://www.i18nguy.com/unicode/c-unicode.html
 *****************************************************************/

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
//#include <tchar.h>
#include "StackFunc.h"
#include "tinyxml.h"
#include "xpath_static.h"


/* Defines */
#define NSIS_MAX_STRLEN 1024

/* Include private stack functions */
#define StackInsert
#define StackDelete
#define StackClear
#include "StackFunc.h"
#include <tchar.h>

typedef struct _xml_stack {
  struct _xml_stack *next;
  struct _xml_stack *prev;
  TiXmlNode *st_node;
} xml_stack;

/* ExDll */
typedef struct _stack_t {
  struct _stack_t *next;
  TCHAR text[1];
} stack_t;

stack_t **g_stacktop;
TCHAR *g_variables;
unsigned int g_stringsize;

#define EXDLL_INIT()        \
{                           \
  g_stacktop=stacktop;      \
  g_variables=variables;    \
  g_stringsize=string_size; \
}

/* Global variables */
TCHAR szBuf[NSIS_MAX_STRLEN];
TCHAR szBuf2[NSIS_MAX_STRLEN];
TCHAR szBuf3[NSIS_MAX_STRLEN];
char ansiBuf[NSIS_MAX_STRLEN];
char ansiBuf2[NSIS_MAX_STRLEN];
int nGoto=0;
int nElement=1;
TiXmlDocument doc;
TiXmlNode *node=&doc;
TiXmlNode *nodeF=0;
TiXmlNode *nodeF2=0;
TiXmlNode *nodeTmp=0;
TiXmlNode *nodeTmp2=0;
TiXmlText *text=0;
TiXmlElement *element=0;
TiXmlAttribute *attribute=0;
TiXmlAttribute *attributeTmp=0;
TiXmlDeclaration *declaration=0;
TiXmlEncoding TIXML_ENCODING=TIXML_DEFAULT_ENCODING;
xml_stack *pStackElement=NULL;
xml_stack *pStackFirst=NULL;
xml_stack *pStackTop=NULL;

/* Funtions prototypes and macros */
int popstring(TCHAR *str, int len);
void pushstring(const TCHAR *str, int len);

/* NSIS functions code */
extern "C" void __declspec(dllexport) _SetCondenseWhiteSpace(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

    if (!lstrcmp(szBuf, TEXT("0")))
      doc.SetCondenseWhiteSpace(false);
    else
      doc.SetCondenseWhiteSpace(true);
  }
}

extern "C" void __declspec(dllexport) _SetEncoding(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

    if (!lstrcmpi(szBuf, TEXT("UTF8"))) TIXML_ENCODING=TIXML_ENCODING_UTF8;
    else if (!lstrcmpi(szBuf, TEXT("LEGACY"))) TIXML_ENCODING=TIXML_ENCODING_LEGACY;
  }
}

void Unicode2Ansi(const TCHAR* unicodestr, char *ansistr)
{
	int lenW = _tcslen(unicodestr);
	int lenA = ::WideCharToMultiByte(CP_ACP, 0, unicodestr, lenW, 0, 0, NULL, NULL);
	if (lenA > 0)
	{
		//ansistr = new char[lenA + 1]; // allocate a final null terminator as well
		::WideCharToMultiByte(CP_ACP, 0, unicodestr, lenW, ansistr, lenA, NULL, NULL);
		ansistr[lenA] = 0; // Set the null terminator yourself
	}
	else
	{
		// handle the error
		ansistr[0] = 0;
	}
}

void Ansi2Unicode(const char *ansistr, TCHAR* unicodestr )
{
	int lenA = lstrlenA(ansistr);
	int lenW;

	lenW = ::MultiByteToWideChar(CP_ACP, 0, ansistr, lenA, 0, 0);
	if (lenW > 0)
	{
		// Check whether conversion was successful
		//unicodestr = ::SysAllocStringLen(0, lenW);
		::MultiByteToWideChar(CP_ACP, 0, ansistr, lenA, unicodestr, lenW);
		unicodestr[lenW] = 0;
	}
	else
	{
		// handle the error
	}
	//		TCHAR str[128];
	//	_stprintf(str,TEXT("ansi len %d uni len %d"),lenA,lenW);
	//MessageBox(NULL,str,0,MB_OK);


}

extern "C" void __declspec(dllexport) _CreateDocument(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
	  // version
    popstring(szBuf, NSIS_MAX_STRLEN);
	Unicode2Ansi(szBuf, ansiBuf);

	TIXML_ENCODING=TIXML_DEFAULT_ENCODING;
    if (!lstrcmpi(szBuf, TEXT("UTF8"))) TIXML_ENCODING=TIXML_ENCODING_UTF8;
    else if (!lstrcmpi(szBuf, TEXT("LEGACY"))) TIXML_ENCODING=TIXML_ENCODING_LEGACY;

	// encoding
	popstring(szBuf, NSIS_MAX_STRLEN);

    if (!lstrcmpi(szBuf, TEXT("UTF8"))) TIXML_ENCODING=TIXML_ENCODING_UTF8;
    else if (!lstrcmpi(szBuf, TEXT("LEGACY"))) TIXML_ENCODING=TIXML_ENCODING_LEGACY;

	TiXmlDeclaration decl(ansiBuf,TIXML_ENCODING==TIXML_ENCODING_UTF8?"UTF8":TIXML_ENCODING==TIXML_ENCODING_LEGACY?"LEGACY":"","");
	//TiXmlDeclaration decl("1.0","UTF8","");
	node = decl.Clone();
	doc.LinkEndChild( node );
  }
}

extern "C" void __declspec(dllexport) _LoadFile(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);
	//TCHAR buf[1024];
	//wsprintf(buf,_T("$0=%s\n"),getuservariable(INST_0));
	char ansiBuf[1024];
	Unicode2Ansi(szBuf,ansiBuf);
    if (doc.LoadFile(ansiBuf, TIXML_ENCODING))
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    else
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _SaveFile(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);
	Unicode2Ansi(szBuf,ansiBuf);

    if ((!*szBuf && doc.SaveFile()) || (*szBuf && doc.SaveFile(ansiBuf)))
	{
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
	}
    else
	{
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
	}
  }
}

extern "C" void __declspec(dllexport) _DeclarationVersion(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    nodeTmp=&doc;

	nodeTmp=nodeTmp->FirstChild();
    if ((nodeTmp) && (declaration=nodeTmp->ToDeclaration()))
    {
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
	  Ansi2Unicode(declaration->Version(),szBuf);
      pushstring(szBuf, NSIS_MAX_STRLEN);
    }
    else
    {
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
    }
  }
}

extern "C" void __declspec(dllexport) _DeclarationEncoding(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    nodeTmp=&doc;
	nodeTmp=nodeTmp->FirstChild();

    if ((nodeTmp) && (declaration=nodeTmp->ToDeclaration()))
    {
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
	  Ansi2Unicode(declaration->Encoding(),szBuf);
      pushstring(szBuf, NSIS_MAX_STRLEN);
    }
    else
    {
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
    }
  }
}

extern "C" void __declspec(dllexport) _DeclarationStandalone(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    nodeTmp=&doc;
	nodeTmp=nodeTmp->FirstChild();
    if ((nodeTmp) && (declaration=nodeTmp->ToDeclaration()))
    {
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
	  Ansi2Unicode(declaration->Standalone(),szBuf);
      pushstring(szBuf, NSIS_MAX_STRLEN);
    }
    else
    {
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
    }
  }
}

extern "C" void __declspec(dllexport) _GetText(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    if (node->ToElement())
    {
	  nodeTmp=node->FirstChild();
      if ((nodeTmp != NULL) && nodeTmp->ToText() != NULL)
      {
		TCHAR uniBuf[NSIS_MAX_STRLEN];
        pushstring(TEXT("0"), NSIS_MAX_STRLEN);
  	    //MessageBoxA(hwndParent,nodeTmp->Value(),0,MB_OK);
		Ansi2Unicode(nodeTmp->Value(),uniBuf);
    	//MessageBox(hwndParent,uniBuf,0,MB_OK);
        pushstring(uniBuf, NSIS_MAX_STRLEN);
        return;
      }
	  else
	  {
		  //MessageBox(hwndParent,TEXT("node no FirstChild or ToText"),0,MB_OK);
	  }
    }
	else
	{
		//int nodeType = (int)node->Type();
		//TCHAR str[128];
		//_stprintf(str,TEXT("Node is no element but %d"),nodeType);
		//MessageBox(hwndParent,str,0,MB_OK);
	}
    pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
    pushstring(TEXT(""), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _SetText(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);
	Unicode2Ansi(szBuf,ansiBuf);

    if (node->ToElement())
    {
       if (nodeTmp=node->FirstChild())
      {
        if (nodeTmp->ToText())
		{
          nodeTmp->SetValue(ansiBuf);
		}
        else
        {
          text=new TiXmlText(ansiBuf);
          node->InsertBeforeChild(nodeTmp, *text);
        }
      }
      else
      {
        text=new TiXmlText(ansiBuf);
        node->InsertEndChild(*text);
      }
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
      return;
    }
    pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _SetCDATA(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

    if (text=node->ToText())
    {
      if (!lstrcmp(szBuf, TEXT("1")))
        text->SetCDATA(true);
      else
        text->SetCDATA(false);
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    }
    else
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _IsCDATA(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    if (text=node->ToText())
    {
      if (text->CDATA() == TRUE)
        pushstring(TEXT("1"), NSIS_MAX_STRLEN);
      else
        pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    }
    else
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _GetNodeValue(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
		Ansi2Unicode(node->Value(),szBuf);
        pushstring(szBuf, NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _SetNodeValue(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);
	Unicode2Ansi(szBuf,ansiBuf);
    node->SetValue(ansiBuf);
  }
}

extern "C" void __declspec(dllexport) _FindNextElement(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    int i;

    popstring(szBuf, NSIS_MAX_STRLEN);

    if (nGoto == 1) goto NextSiblingElement;
    else if (nGoto != 0) goto End;

    nGoto=1;
    StackInsert((stack **)&pStackFirst, (stack **)&pStackTop, (stack **)&pStackElement, -1, sizeof(xml_stack));
    pStackElement->st_node=node;

    while (nElement != 0)
    {
      --nElement;
      nodeF=pStackTop->st_node;
      StackDelete((stack **)&pStackFirst, (stack **)&pStackTop, (stack *)pStackTop);

      if ((!*szBuf && (nodeF2=nodeF->FirstChildElement())) || (*szBuf && (nodeF2=nodeF->FirstChildElement(ansiBuf))))
      {
        Return:
        node=nodeF2;
        pushstring(TEXT("0"), NSIS_MAX_STRLEN);
		Ansi2Unicode(node->Value(),szBuf);
        pushstring(szBuf, NSIS_MAX_STRLEN);
        return;

        NextSiblingElement:
        if ((!*szBuf && (nodeF2=nodeF2->NextSiblingElement())) || (*szBuf && (nodeF2=nodeF2->NextSiblingElement(ansiBuf))))
          goto Return;
      }
      if (nodeF2=nodeF->FirstChildElement())
      {
        i=0;

        do
        {
          ++i;
          ++nElement;
          StackInsert((stack **)&pStackFirst, (stack **)&pStackTop, (stack **)&pStackElement, i, sizeof(xml_stack));
          pStackElement->st_node=nodeF2;
        }
        while (nodeF2=nodeF2->NextSiblingElement());
      }
    }
    nGoto=-1;

    End:
    pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
    pushstring(TEXT(""), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _FindCloseElement(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  nGoto=0;
  StackClear((stack **)&pStackFirst, (stack **)&pStackTop);
}

extern "C" void __declspec(dllexport) _RootElement(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    if (nodeTmp=doc.RootElement())
    {
      node=nodeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
	  Ansi2Unicode(node->Value(),szBuf);
      pushstring(szBuf, NSIS_MAX_STRLEN);
    }
    else
    {
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
    }
  }
}

extern "C" void __declspec(dllexport) _FirstChildElement(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

    //ANif ((!*szBuf && (nodeTmp=node->FirstChildElement())) || (*szBuf && (nodeTmp=node->FirstChildElement(szBuf))))
    //{
    //  node=nodeTmp;
    //  pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    //  pushstring(node->Value(), NSIS_MAX_STRLEN);
    //}
    //else
    //{
    //  pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
    //  pushstring(TEXT(""), NSIS_MAX_STRLEN);
    //}
  }
}

extern "C" void __declspec(dllexport) _FirstChild(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

    //ANif ((!*szBuf && (nodeTmp=node->FirstChild())) || (*szBuf && (nodeTmp=node->FirstChild(szBuf))))
    //{
    //  node=nodeTmp;
    //  pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    //  pushstring(node->Value(), NSIS_MAX_STRLEN);
    //}
    //else
    //{
    //  pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
    //  pushstring(TEXT(""), NSIS_MAX_STRLEN);
    //}
  }
}

extern "C" void __declspec(dllexport) _LastChild(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

    //ANif ((!*szBuf && (nodeTmp=node->LastChild())) || (*szBuf && (nodeTmp=node->LastChild(szBuf))))
    //{
    //  node=nodeTmp;
    //  pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    //  pushstring(node->Value(), NSIS_MAX_STRLEN);
    //}
    //else
    //{
    //  pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
    //  pushstring(TEXT(""), NSIS_MAX_STRLEN);
    //}
  }
}

extern "C" void __declspec(dllexport) _Parent(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    if (nodeTmp=node->Parent())
    {
      node=nodeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
	  Ansi2Unicode(node->Value(),szBuf);
      pushstring(szBuf, NSIS_MAX_STRLEN);
    }
    else
    {
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
    }
  }
}

extern "C" void __declspec(dllexport) _NoChildren(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    if (node->NoChildren() == TRUE)
      pushstring(TEXT("1"), NSIS_MAX_STRLEN);
    else
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _NextSiblingElement(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

    //ANif ((!*szBuf && (nodeTmp=node->NextSiblingElement())) || (*szBuf && (nodeTmp=node->NextSiblingElement(szBuf))))
    //{
    //  node=nodeTmp;
    //  pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    //  pushstring(node->Value(), NSIS_MAX_STRLEN);
    //}
    //else
    //{
    //  pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
    //  pushstring(TEXT(""), NSIS_MAX_STRLEN);
    //}
  }
}

extern "C" void __declspec(dllexport) _NextSibling(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

    //ANif ((!*szBuf && (nodeTmp=node->NextSibling())) || (*szBuf && (nodeTmp=node->NextSibling(szBuf))))
    //{
    //  node=nodeTmp;
    //  pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    //  pushstring(node->Value(), NSIS_MAX_STRLEN);
    //}
    //else
    //{
    //  pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
    //  pushstring(TEXT(""), NSIS_MAX_STRLEN);
    //}
  }
}

extern "C" void __declspec(dllexport) _PreviousSibling(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

    //ANif ((!*szBuf && (nodeTmp=node->PreviousSibling())) || (*szBuf && (nodeTmp=node->PreviousSibling(szBuf))))
    //{
    //  node=nodeTmp;
    //  pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    //  pushstring(node->Value(), NSIS_MAX_STRLEN);
    //}
    //else
    //{
    //  pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
    //  pushstring(TEXT(""), NSIS_MAX_STRLEN);
    //}
  }
}

extern "C" void __declspec(dllexport) _InsertAfterNode(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

	Unicode2Ansi(szBuf,ansiBuf);

	nodeTmp2=(TiXmlNode *)atoi(ansiBuf);
	nodeTmp=node->Parent();
    if ((nodeTmp2) && (nodeTmp) && (nodeTmp=nodeTmp->InsertAfterChild(node, *nodeTmp2)))
    {
      node=nodeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    }
    else
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _InsertBeforeNode(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

  //AN  if ((nodeTmp2=(TiXmlNode *)atoi(szBuf)) && (nodeTmp=node->Parent()) && (nodeTmp=nodeTmp->InsertBeforeChild(node, *nodeTmp2)))
  //  {
  //    node=nodeTmp;
  //    pushstring("0", NSIS_MAX_STRLEN);
  //  }
  //  else
  //    pushstring("-1", NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _InsertEndChild(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

	Unicode2Ansi(szBuf, ansiBuf);

    if (node->ToElement() && (nodeTmp2=(TiXmlNode *)atoi(ansiBuf)) && (nodeTmp=node->InsertEndChild(*nodeTmp2)))
    {
      node=nodeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    }
    else
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _InsertRoot(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

	Unicode2Ansi(szBuf, ansiBuf);

	nodeTmp2=(TiXmlNode *)atoi(ansiBuf);
    if ((nodeTmp2) && (nodeTmp=doc.InsertEndChild(*nodeTmp2)))
    {
      node=nodeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    }
    else
	{
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
	}
  }
}

extern "C" void __declspec(dllexport) _ReplaceNode(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

    //ANif ((nodeTmp2=(TiXmlNode *)atoi(szBuf)) && (nodeTmp=node->Parent()) && (nodeTmp->ReplaceChild(node, *nodeTmp2)))
    //  pushstring("0", NSIS_MAX_STRLEN);
    //else
    //  pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _RemoveNode(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    if ((nodeTmp=node->Parent()) && nodeTmp->RemoveChild(node))
    {
      node=nodeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    }
    else
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _RemoveAllChild(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    node->Clear();
  }
}

extern "C" void __declspec(dllexport) _CreateText(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);
	Unicode2Ansi(szBuf,ansiBuf);

    if (text=new TiXmlText(ansiBuf))
    {
      _itoa((int)text, ansiBuf, 10);
      pushstring(szBuf, NSIS_MAX_STRLEN);
    }
    else
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _CreateNode(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    TiXmlElement element("");

    popstring(szBuf, NSIS_MAX_STRLEN);
	Unicode2Ansi(szBuf,ansiBuf);

    if (element.Parse(ansiBuf, 0, TIXML_ENCODING))
    {
      _itoa((int)element.Clone(), ansiBuf, 10);
	  Ansi2Unicode(ansiBuf, szBuf);
      pushstring(szBuf, NSIS_MAX_STRLEN);
    }
    else
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _CloneNode(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
//AN    _itoa((int)node->Clone(), szBuf, 10);

    pushstring(szBuf, NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _FreeNode(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

    //ANif (nodeTmp=(TiXmlNode *)atoi(szBuf))
    //{
    //  nodeTmp->~TiXmlNode();
    //  nodeTmp=0;
    //  pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    //}
    //else
    //  pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _NodeHandle(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    _itoa((int)node, ansiBuf, 10);

	Ansi2Unicode(ansiBuf,szBuf);
    pushstring(szBuf, NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _GotoHandle(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

	Unicode2Ansi(szBuf,ansiBuf);
    if (nodeTmp=(TiXmlNode *)atoi(ansiBuf))
    {
      node=nodeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    }
    else
	{
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
	}
  }
}

extern "C" void __declspec(dllexport) _ElementPath(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    int i;
    szBuf[0]='\0';
    nodeTmp=node;

    if (nodeTmp != &doc && !nodeTmp->ToElement())
	{
		nodeTmp=nodeTmp->Parent();
	}

    if (nodeTmp != &doc)
    {
      do
      {
        nodeTmp2=nodeTmp;
        i=1;

        while (nodeTmp2=nodeTmp2->PreviousSibling(nodeTmp->Value()))
		{
          if (nodeTmp2->ToElement()) ++i;
		}

		Ansi2Unicode(nodeTmp->Value(),szBuf3);
        if (i != 1)
		{
          _stprintf(szBuf2, TEXT("/%s[%d]%s"), szBuf3, i, szBuf);
		}
        else
		{
          _stprintf(szBuf2, TEXT("/%s%s"), szBuf3, szBuf);
		}

        lstrcpy(szBuf, szBuf2);
      }
      while ((nodeTmp=nodeTmp->Parent()) && nodeTmp != &doc);
    }
    pushstring(szBuf, NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _GotoPath(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    char *pBuf=&ansiBuf[0];
    char *pBuf2=&ansiBuf[0];
    int i;
    BOOL bExit=FALSE;
    nodeTmp=node;

    popstring(szBuf, NSIS_MAX_STRLEN);
    Unicode2Ansi(szBuf, ansiBuf);

    if (*pBuf2 == '\0')
    {
      nodeTmp=&doc;
      bExit=TRUE;
    }
    else if (*pBuf2 == '/')
      nodeTmp=&doc;
    else if (nodeTmp != &doc && !nodeTmp->ToElement())
      goto Error;
    else --pBuf2;

    while (nodeTmp && bExit == FALSE)
    {
      i=1;
      pBuf=++pBuf2;

      while (*pBuf2 != '/' && *pBuf2 != '\0')
      {
        if (*pBuf2 == '[')
        {
          *pBuf2='\0';
          i=atoi(++pBuf2);

          if (i == 0) goto Error;
        }
        else ++pBuf2;
      }

	  if (*pBuf2 == '/')
	  { 
		  *pBuf2='\0';
	  }
	  else
	  { 
		  bExit=TRUE;
	  }

      if (i > 0)
      {
        if ((!*pBuf && (nodeTmp=nodeTmp->FirstChildElement())) || (*pBuf && (nodeTmp=nodeTmp->FirstChildElement(pBuf))))
        {
          do
          {
            --i;
          }
          while (i != 0 && ((!*pBuf && (nodeTmp=nodeTmp->NextSiblingElement())) || (*pBuf && (nodeTmp=nodeTmp->NextSiblingElement(pBuf)))));
        }
      }
      else
      {
        if ((!*pBuf && (nodeTmp=nodeTmp->LastChild())) || (*pBuf && (nodeTmp=nodeTmp->LastChild(pBuf))))
        {
          do
          {
            if (nodeTmp->ToElement()) ++i;
          }
          while (i != 0 && ((!*pBuf && (nodeTmp=nodeTmp->PreviousSibling())) || (*pBuf && (nodeTmp=nodeTmp->PreviousSibling(pBuf)))));
        }
      }
    }

    if (nodeTmp && bExit == TRUE)
    {
      node=nodeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
      return;
    }

    Error:
    pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _XPathString(HWND hwndParent, int string_size,
                       TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    TIXML_STRING S_res;

    popstring(szBuf, NSIS_MAX_STRLEN);

    //if (TinyXPath::o_xpath_string(node, szBuf, S_res))
    //{
    //  pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    //  pushstring(S_res.c_str(), NSIS_MAX_STRLEN);
    //}
    //else
    //{
    //  pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
    //  pushstring("", NSIS_MAX_STRLEN);
    //}
  }
}

extern "C" void __declspec(dllexport) _XPathNode(HWND hwndParent, int string_size,
                       TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

	const TiXmlNode *nodeTmp1=0;
    //if (TinyXPath::o_xpath_node(node, szBuf, nodeTmp1))
    //{
    //  node=const_cast<TiXmlNode*>(nodeTmp1);
    //  pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    //}
    //else
    //  pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _XPathAttribute(HWND hwndParent, int string_size,
                       TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

	const TiXmlAttribute *attributeTmp1=0;

    //if (TinyXPath::o_xpath_attribute(node, szBuf, attributeTmp1))
    //{
    //  attribute=const_cast<TiXmlAttribute*>(attributeTmp1);
    //  pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    //}
    //else
    //  pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _NodeType(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    int nType;

    nType=node->Type();

	//TCHAR str[128];
	//_stprintf(str,TEXT("Node type %d"),nType);
	//MessageBox(hwndParent,str,0,MB_OK);
		//	DOCUMENT,
		//ELEMENT,
		//COMMENT,
		//UNKNOWN,
		//TEXT,
		//DECLARATION,
		//TYPECOUNT


	switch (nType)
	{
	case 0:pushstring(TEXT("DOCUMENT"), NSIS_MAX_STRLEN); break;
	case 1:pushstring(TEXT("ELEMENT"), NSIS_MAX_STRLEN); break;
	case 2:pushstring(TEXT("COMMENT"), NSIS_MAX_STRLEN); break;
	case 3:pushstring(TEXT("UNKNOWN"), NSIS_MAX_STRLEN); break;
	case 4:pushstring(TEXT("TEXT"), NSIS_MAX_STRLEN); break;
	case 5:pushstring(TEXT("DECLARATION"), NSIS_MAX_STRLEN); break;
	case 6:pushstring(TEXT("TYPECOUNT"), NSIS_MAX_STRLEN); break;
	default:
		pushstring(TEXT("UNKNOWN2"), NSIS_MAX_STRLEN);
	}
    //if (nType == 1) pushstring(TEXT("ELEMENT"), NSIS_MAX_STRLEN);
    //else if (nType == 2) pushstring(TEXT("COMMENT"), NSIS_MAX_STRLEN);
    //else if (nType == 3) pushstring(TEXT("DOCUMENT"), NSIS_MAX_STRLEN);
    //else if (nType == 4) pushstring(TEXT("TEXT"), NSIS_MAX_STRLEN);
    //else if (nType == 5) pushstring(TEXT("DECLARATION"), NSIS_MAX_STRLEN);
    //else pushstring(TEXT("UNKNOWN"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _Coordinate(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    //AN_itoa(node->Row(), szBuf, 10);
    //AN_itoa(node->Column(), szBuf2, 10);

    pushstring(szBuf2, NSIS_MAX_STRLEN);
    pushstring(szBuf, NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _GetAttribute(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);
	Unicode2Ansi(szBuf, ansiBuf);

	element=node->ToElement();

    if ((element) && (attributeTmp=element->FirstAttribute()))
    {
      do
      {
        if (!lstrcmpA(ansiBuf, attributeTmp->Name()))
        {
          attribute=attributeTmp;
          pushstring(TEXT("0"), NSIS_MAX_STRLEN);
		  Ansi2Unicode(attribute->Value(),szBuf);
          pushstring(szBuf, NSIS_MAX_STRLEN);
          return;
        }
      }
      while (attributeTmp=attributeTmp->Next());
    }
    pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
    pushstring(TEXT(""), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _SetAttribute(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);
    popstring(szBuf2, NSIS_MAX_STRLEN);

	Unicode2Ansi(szBuf,ansiBuf);
	Unicode2Ansi(szBuf2,ansiBuf2);

	element=node->ToElement();
    if (element)
    {
      element->SetAttribute(ansiBuf, ansiBuf2);
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    }
    else
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _RemoveAttribute(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);
	Unicode2Ansi(szBuf,ansiBuf);

	element=node->ToElement();

    if (element)
    {
      element->RemoveAttribute(ansiBuf);
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);
    }
    else
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
  }
}

extern "C" void __declspec(dllexport) _FirstAttribute(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
	  element=node->ToElement();
    if ((element) && (attributeTmp=element->FirstAttribute()))
    {
      attribute=attributeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);

  	  Ansi2Unicode(attribute->Value(),szBuf);
      pushstring(szBuf, NSIS_MAX_STRLEN);

  	  Ansi2Unicode(attribute->Name(),szBuf2);
      pushstring(szBuf2, NSIS_MAX_STRLEN);
    }
    else
    {
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
    }
  }
}

extern "C" void __declspec(dllexport) _LastAttribute(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
	  element=node->ToElement();

    if ((element) && (attributeTmp=element->LastAttribute()))
    {
      attribute=attributeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);

  	  Ansi2Unicode(attribute->Value(),szBuf);
      pushstring(szBuf, NSIS_MAX_STRLEN);

  	  Ansi2Unicode(attribute->Name(),szBuf2);
      pushstring(szBuf2, NSIS_MAX_STRLEN);
    }
    else
    {
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
    }
  }
}

extern "C" void __declspec(dllexport) _NextAttribute(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    if (attribute && (attributeTmp=attribute->Next()))
    {
      attribute=attributeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);

  	  Ansi2Unicode(attribute->Value(),szBuf);
      pushstring(szBuf, NSIS_MAX_STRLEN);

  	  Ansi2Unicode(attribute->Name(),szBuf2);
      pushstring(szBuf2, NSIS_MAX_STRLEN);
    }
    else
    {
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
    }
  }
}

extern "C" void __declspec(dllexport) _PreviousAttribute(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    if (attribute && (attributeTmp=attribute->Previous()))
    {
      attribute=attributeTmp;
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);

  	  Ansi2Unicode(attribute->Value(),szBuf);
      pushstring(szBuf, NSIS_MAX_STRLEN);

  	  Ansi2Unicode(attribute->Name(),szBuf2);
      pushstring(szBuf2, NSIS_MAX_STRLEN);
    }
    else
    {
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
    }
  }
}

extern "C" void __declspec(dllexport) _CurrentAttribute(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    if (attribute)
    {
      pushstring(TEXT("0"), NSIS_MAX_STRLEN);

  	  Ansi2Unicode(attribute->Value(),szBuf);
      pushstring(szBuf, NSIS_MAX_STRLEN);

  	  Ansi2Unicode(attribute->Name(),szBuf2);
      pushstring(szBuf2, NSIS_MAX_STRLEN);
    }
    else
    {
      pushstring(TEXT("-1"), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
      pushstring(TEXT(""), NSIS_MAX_STRLEN);
    }
  }
}

extern "C" void __declspec(dllexport) _SetAttributeName(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);
	Unicode2Ansi(szBuf,ansiBuf);
    attribute->SetName(ansiBuf);
  }
}

extern "C" void __declspec(dllexport) _SetAttributeValue(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
  EXDLL_INIT();
  {
    popstring(szBuf, NSIS_MAX_STRLEN);

	Unicode2Ansi(szBuf,ansiBuf);

    attribute->SetValue(ansiBuf);
  }
}

extern "C" void __declspec(dllexport) _Unload(HWND hwndParent, int string_size,
                                      TCHAR *variables, stack_t **stacktop)
{
}

BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
  return TRUE;
}


/* Functions */
//Function: Removes the element from the top of the NSIS stack and puts it in the buffer
int popstring(TCHAR *str, int len)
{
  stack_t *th;

  if (!g_stacktop || !*g_stacktop) return 1;
  th=(*g_stacktop);
  lstrcpyn(str, th->text, len);
  *g_stacktop=th->next;
  GlobalFree((HGLOBAL)th);
  return 0;
}

//Function: Adds an element to the top of the NSIS stack
void pushstring(const TCHAR *str, int len)
{
  stack_t *th;

  if (!g_stacktop) return;
  th=(stack_t*)GlobalAlloc(GPTR, sizeof(stack_t) + len);
  lstrcpyn(th->text, str, len);
  th->next=*g_stacktop;
  *g_stacktop=th;
}
